package com.platform.system.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.platform.common.constant.Constants;
import com.platform.common.constant.HttpStatus;
import com.platform.common.core.domain.AjaxResult;
import com.platform.common.core.domain.entity.SysUser;
import com.platform.common.core.page.TableDataInfo;
import com.platform.common.core.redis.RedisCache;
import com.platform.common.enums.DeviceStatusEnum;
import com.platform.common.enums.ResultEnum;
import com.platform.common.exception.BusinessException;
import com.platform.common.utils.DateUtils;
import com.platform.common.utils.SecurityUtils;
import com.platform.common.utils.bean.BeanUtils;
import com.platform.common.utils.poi.ExcelUtil;
import com.platform.common.utils.sign.AESUtils;
import com.platform.common.utils.uuid.SnowflakeIdWorker;
import com.platform.system.domain.dto.device.*;
import com.platform.system.domain.entity.device.DeviceInfo;
import com.platform.system.domain.vo.device.DeviceInfoVo;
import com.platform.system.domain.vo.device.HumanModelManagerVo;
import com.platform.system.domain.vo.device.TenantAuthAiVo;
import com.platform.system.enums.TopicEnums;
import com.platform.system.logic.DeviceInfoLogic;
import com.platform.system.mapper.device.DeviceInfoMapper;
import com.platform.system.mqtt.utils.MqttService;
import com.platform.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Huangkai
 */
@Service
@Slf4j
public class SysDeviceInfoServiceImpl  extends ServiceImpl<DeviceInfoMapper, DeviceInfo> implements ISysDeviceInfoService {

    @Resource
    DeviceInfoMapper deviceInfoMapper;

    @Resource
    ISysDeviceInfoService deviceInfoService;

    @Resource
    DeviceInfoLogic deviceInfoLogic;

    @Resource
    ISysTenantAuthAiService sysTenantAuthAiService;

    @Resource
    ISysHumanModelManagerService sysHumanModelManagerService;

    @Resource
    ISysConfigService sysConfigService;


    @Autowired
    private RedisCache redisCache;

    @Override
    public String aiuiOperation(HttpServletRequest request) {
        String getContentType = request.getMethod();
        String token = sysConfigService.selectConfigByKey("aiuiToken");
        if("GET".equals(getContentType)){
            return deviceInfoLogic.authAiui(request,token);
        }else{
            deviceInfoLogic.aiuiDataOperation(request);
        }

        return null;
    }

    @Override
    public AjaxResult setDefaultUserDevice(DeviceInfoVo deviceInfoVo) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getWebUserUid, deviceInfoVo.getWebUserUid());
        List<DeviceInfo> deviceInfoList = deviceInfoMapper.selectList(deviceInfoLambdaQueryWrapper);
        if(CollectionUtils.isEmpty(deviceInfoList)){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        for(int i=0; i < deviceInfoList.size(); i++){
            DeviceInfo deviceInfo = deviceInfoList.get(i);
            if(deviceInfo.getUid().equals(deviceInfoVo.getUid()) && deviceInfo.getIsUsed().equals(Constants.NUM_ONE)){
                return AjaxResult.success();
            }
            if(deviceInfo.getUid().equals(deviceInfoVo.getUid())){
                deviceInfoVo.setIsUsed(Constants.NUM_ONE);
                updateDeviceInfo(deviceInfoVo);
            }
            //不等于值
            if(!deviceInfo.getUid().equals(deviceInfoVo.getUid())){
                //修改之前的
                if(deviceInfo.getIsUsed().equals(Constants.NUM_ONE)){
                    DeviceInfoVo setDeviceInfoVo = new DeviceInfoVo();
                    setDeviceInfoVo.setUid(deviceInfo.getUid());
                    setDeviceInfoVo.setIsUsed(Constants.NUM_ONE);
                    updateDeviceInfo(setDeviceInfoVo);
                }
            }
        }
        return AjaxResult.success();
    }

    @Override
    public DeviceInfoDto selectDeviceInfoDtoByKey(String key) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getAuthKey, key);
        DeviceInfo deviceInfo = deviceInfoMapper.selectOne(deviceInfoLambdaQueryWrapper);
        if(deviceInfo != null){
            DeviceInfoDto deviceInfoDto = new DeviceInfoDto();
            BeanUtils.copyProperties(deviceInfo, deviceInfoDto);
            return deviceInfoDto;
        }
        return null;
    }

    @Override
    public List<DeviceInfoDto> selectDeviceInfoByRegexp(String macRegexp) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.likeRight(StringUtils.isNotEmpty(macRegexp), DeviceInfo::getMac, macRegexp);
        List<DeviceInfo> deviceInfoList = deviceInfoMapper.selectList(deviceInfoLambdaQueryWrapper);
        if(!CollectionUtils.isEmpty(deviceInfoList)){
            String json = JSONArray.toJSONString(deviceInfoList);
            List<DeviceInfoDto> deviceInfoDtoList = JSONArray.parseArray(json, DeviceInfoDto.class);
            return deviceInfoDtoList;
        }
        return null;
    }

    @Override
    public TableDataInfo selectDeviceInfoList(DeviceInfoVo deviceInfoVo) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.like(StringUtils.isNotEmpty(deviceInfoVo.getName()), DeviceInfo::getName, deviceInfoVo.getName());
        deviceInfoLambdaQueryWrapper.like(StringUtils.isNotEmpty(deviceInfoVo.getSn()), DeviceInfo::getSn, deviceInfoVo.getSn());
        deviceInfoLambdaQueryWrapper.like(StringUtils.isNotEmpty(deviceInfoVo.getMac()), DeviceInfo::getMac, deviceInfoVo.getMac());
        deviceInfoLambdaQueryWrapper.orderByDesc(DeviceInfo::getCreateTime);
        Page<DeviceInfo> page = new Page<>();
        page.setCurrent(deviceInfoVo.getPageNum());
        page.setSize(deviceInfoVo.getPageSize());
        IPage<DeviceInfo> deviceInfoIPage = deviceInfoMapper.selectPage(page, deviceInfoLambdaQueryWrapper);
        TableDataInfo rspData = new TableDataInfo();
        List<DeviceInfo> list =  deviceInfoIPage.getRecords();
        List<DeviceInfoDto> aiUiConfigDtoList = new ArrayList<>();
        if(list != null || list.size() > 0){
            list.forEach(deviceInfo -> {
                DeviceInfoDto deviceInfoDto = new DeviceInfoDto();
                BeanUtils.copyProperties(deviceInfo, deviceInfoDto);
                deviceInfoLogic.buildDeviceInfo(deviceInfoDto);
                aiUiConfigDtoList.add(deviceInfoDto);
            });
        }
        rspData.setRows(aiUiConfigDtoList);
        rspData.setTotal(deviceInfoIPage.getTotal());
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        return rspData;
    }

    @Override
    public AjaxResult heartDeviceInfo(DeviceInfoVo deviceInfoVo) {
        DeviceInfoDto deviceInfoDto = deviceInfoService.selectDeviceInfoByMac(deviceInfoVo);
        if(deviceInfoDto == null){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setStatus(Constants.NUM_ONE);
        LambdaQueryWrapper<DeviceInfo> statusUpdateWrapper = new QueryWrapper<DeviceInfo>().lambda();
        statusUpdateWrapper.eq(DeviceInfo::getUid, deviceInfoDto.getUid());
        deviceInfo.setUpdateTime(new Date());
        deviceInfo.update(statusUpdateWrapper);

        //保存上报信息
        redisCache.setCacheObject(deviceInfoDto.getUid() + "deviceHeart", deviceInfo);
        return AjaxResult.success();
    }

    @Override
    public TableDataInfo selectTenantAuthAiByDeviceInfo(DeviceInfoVo deviceInfoVo) {
        TenantAuthAiVo tenantAuthAiVo = new TenantAuthAiVo();
        tenantAuthAiVo.setTenantUid(deviceInfoVo.getTenantUid());
        TenantAuthAiDto tenantAuthAiDto = sysTenantAuthAiService.selectTenantAuthAiByTenantUid(tenantAuthAiVo);
        TableDataInfo rspData = new TableDataInfo();
        if(tenantAuthAiDto == null ){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        if(tenantAuthAiDto.getIsAll().equals(Constants.NUM_ONE)){
            HumanModelManagerVo humanModelManagerVo = new HumanModelManagerVo();
            humanModelManagerVo.setPageNum(deviceInfoVo.getPageNum());
            humanModelManagerVo.setPageSize(deviceInfoVo.getPageSize());
            return sysHumanModelManagerService.selectHumanModelManagerList(humanModelManagerVo);
        }else{
            TenantAuthAiDto tenantAuthAiDtoResult = new TenantAuthAiDto();
            List<String> humanUidList = JSONArray.parseArray(tenantAuthAiDto.getHumanUidList(), String.class);
            List<HumanModelManagerDto> humanModelManagerDtoList = sysHumanModelManagerService.selectHumanModelManagerListByUidList(humanUidList);
            tenantAuthAiDtoResult.setHumanModelManagerDtoList(humanModelManagerDtoList);
            rspData.setRows(humanModelManagerDtoList);
            rspData.setTotal(humanModelManagerDtoList.size());
        }
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        return rspData;
    }

    @Override
    public List<DeviceInfoDto> selectDeviceInfoDtoByUserId(DeviceInfoVo deviceInfoVo) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getWebUserUid, deviceInfoVo.getWebUserUid());
        List<DeviceInfo> deviceInfoList = deviceInfoMapper.selectList(deviceInfoLambdaQueryWrapper);
        List<DeviceInfoDto> deviceInfoDtoList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(deviceInfoList)){
            String str = JSONArray.toJSONString(deviceInfoList);
            deviceInfoDtoList = JSONArray.parseArray(str, DeviceInfoDto.class);
            List<String> humanUidList = deviceInfoDtoList.stream().map(DeviceInfoDto::getHumanCharacterUid).collect(Collectors.toList());
            List<HumanModelManagerDto> humanModelManagerDtoList = sysHumanModelManagerService.selectHumanModelManagerListByUidList(humanUidList);
            Map<String, List<HumanModelManagerDto>> listMap = humanModelManagerDtoList.stream().collect(Collectors.groupingBy(u ->u.getUid()));
            deviceInfoDtoList.forEach(deviceInfoDto -> {
                if(listMap.containsKey(deviceInfoDto.getHumanCharacterUid())){
                    deviceInfoDto.setHumanModelManagerDto(listMap.get(deviceInfoDto.getHumanCharacterUid()).get(0));
                }
            });
        }
        return deviceInfoDtoList;
    }

    @Override
    public Long getDeviceOnLineCount() {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getStatus, Constants.NUM_ONE);
        Long count = deviceInfoMapper.selectCount(deviceInfoLambdaQueryWrapper);
        return count;
    }

    @Override
    public DeviceInfoDto selectDeviceInfoByMac(DeviceInfoVo deviceInfoVo) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getSn, deviceInfoVo.getSn());
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getMac, deviceInfoVo.getMac());
        DeviceInfo deviceInfo = deviceInfoMapper.selectOne(deviceInfoLambdaQueryWrapper);
        if(deviceInfo != null){
            DeviceInfoDto deviceInfoDto = new DeviceInfoDto();
            BeanUtils.copyProperties(deviceInfo, deviceInfoDto);
            return deviceInfoDto;
        }
        return null;
    }

    @Override
    public AjaxResult activateDevice(DeviceInfoVo deviceInfoVo) {
        DeviceInfoDto deviceInfoDto = deviceInfoService.selectDeviceInfoByMac(deviceInfoVo);
        if(deviceInfoDto == null){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        //如果是非空，已经激活过了
        if(StringUtils.isNotEmpty(deviceInfoDto.getWebUserUid())){
            if(deviceInfoDto.getWebUserUid().equals(deviceInfoVo.getWebUserUid())){
                return AjaxResult.success(deviceInfoDto);
            }
        }
        //激活状态
        if(deviceInfoDto.getStatus().equals(DeviceStatusEnum.ACTIVATE.getCode())){
            throw new BusinessException(ResultEnum.ACTIVATE_STATUS);
        }
        Date currentTime = new Date();
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getUid, deviceInfoDto.getUid());
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setWebUserUid(deviceInfoVo.getWebUserUid());
        deviceInfo.setStatus(DeviceStatusEnum.ACTIVATE.getCode());
        deviceInfo.setActivateTime(currentTime);
        Long time = currentTime.getTime();
        log.info("时间戳{}", time);
        try{
            DeviceInfo setKeyObject = new DeviceInfo();
            setKeyObject.setMac(deviceInfoDto.getMac());
            setKeyObject.setSn(deviceInfoDto.getSn());
            String key = AESUtils.Encrypt(JSONObject.toJSONString(setKeyObject), String.valueOf(time) + "000");
            log.info("秘钥{}", key);
            deviceInfo.setAuthKey(key);
        }catch (Exception e){
            e.printStackTrace();
        }
        deviceInfo.update(deviceInfoLambdaQueryWrapper);
        //激活状态，直接发送通知
        DeviceInfoDto getDeviceInfoDto = deviceInfoService.selectDeviceInfo(deviceInfoDto.getUid());
        deviceInfoLogic.publishDeviceInfo(getDeviceInfoDto);
        return AjaxResult.success(deviceInfoDto);
    }

    @Override
    public void getImportTemplate(HttpServletResponse response) {
        ExcelUtil<DeviceInfoVo> util = new ExcelUtil<>(DeviceInfoVo.class);
        util.importTemplateExcel(response, "设备数据导入数据模板");
    }

    @Override
    public AjaxResult importData(MultipartFile file) throws IOException {
        if(file == null || file.isEmpty()){
            throw new BusinessException(ResultEnum.FILE_NOT_EXIST);
        }
        ExcelUtil<DeviceInfoVo> deviceInfoVoExcelUtil = new ExcelUtil<>(DeviceInfoVo.class);
        List<DeviceInfoVo> exportChipDtoList = deviceInfoVoExcelUtil.importExcel(file.getInputStream());
        if(!CollectionUtils.isEmpty(exportChipDtoList)){
            if(exportChipDtoList.size() > 100){
                throw new BusinessException(ResultEnum.MAX_DEVICE_UPLOAD_COUNT);
            }
            exportChipDtoList.forEach(deviceInfoVo -> {
                DeviceInfoDto deviceInfoDto = selectDeviceInfoByMac(deviceInfoVo);
                if(deviceInfoDto == null){
                    insertDeviceInfo(deviceInfoVo);
                }
            });

        }
        return AjaxResult.success("导入成功");

    }

    @Override
    public DeviceInfoDto selectDeviceInfo(String uid) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getUid, uid);
        DeviceInfo deviceInfo = deviceInfoMapper.selectOne(deviceInfoLambdaQueryWrapper);
        if(deviceInfo != null) {
            DeviceInfoDto deviceInfoDto = new DeviceInfoDto();
            BeanUtils.copyProperties(deviceInfo, deviceInfoDto);
            return deviceInfoDto;
        }
        return null;
    }

    @Override
    public AjaxResult updateDeviceInfoLogStatus(DeviceInfoVo deviceInfoVo) {
        DeviceInfoDto deviceInfoDto = deviceInfoService.selectDeviceInfo(deviceInfoVo.getUid());
        if(deviceInfoDto == null){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setIsUploadLog(Constants.NUM_ZERO);
        if(deviceInfoDto.getIsUploadLog() == Constants.NUM_ZERO){
            deviceInfo.setIsUploadLog(Constants.NUM_ONE);
        }
        LambdaQueryWrapper<DeviceInfo> statusUpdateWrapper = new QueryWrapper<DeviceInfo>().lambda();
        statusUpdateWrapper.eq(DeviceInfo::getUid, deviceInfoVo.getUid());
        deviceInfo.setUpdateTime(new Date());
        deviceInfo.update(statusUpdateWrapper);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult updateDeviceInfoStatus(DeviceInfoVo deviceInfoVo) {
        DeviceInfoDto deviceInfoDto = deviceInfoService.selectDeviceInfo(deviceInfoVo.getUid());
        if(deviceInfoDto == null){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setStatus(deviceInfoVo.getStatus());
        LambdaQueryWrapper<DeviceInfo> statusUpdateWrapper = new QueryWrapper<DeviceInfo>().lambda();
        statusUpdateWrapper.eq(DeviceInfo::getUid, deviceInfoVo.getUid());
        deviceInfo.setUpdateTime(new Date());
        deviceInfo.update(statusUpdateWrapper);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult insertDeviceInfo(DeviceInfoVo deviceInfoVo) {
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setUid(SnowflakeIdWorker.getSnowflakeIdWorker());
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        deviceInfo.setTenantUid(sysUser.getTenantUid());
        deviceInfo.setSn(deviceInfoVo.getSn());
        deviceInfo.setAiuiUid(deviceInfoVo.getAiuiUid());
        deviceInfo.setModelAppUid(deviceInfoVo.getModelAppUid());
        deviceInfo.setHumanCharacterUid(deviceInfoVo.getHumanCharacterUid());
        deviceInfo.setStatus(DeviceStatusEnum.WAIT_ACTIVATE.getCode());
        deviceInfo.setAuthStatus(Constants.NUM_ZERO);
        deviceInfo.setIsUploadLog(Constants.NUM_ZERO);
        deviceInfo.setMac(deviceInfoVo.getMac());
        deviceInfo.setName(deviceInfoVo.getName());
        deviceInfo.setUpdateTime(new Date());
        deviceInfo.setCreateTime(new Date());
        deviceInfo.insert();
        return AjaxResult.success();
    }

    @Override
    public AjaxResult deleteDeviceInfoList(DeviceInfoVo deviceInfoVo) {
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.in(DeviceInfo::getUid, deviceInfoVo.getUidList());
        deviceInfoMapper.delete(deviceInfoLambdaQueryWrapper);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult updateDeviceInfo(DeviceInfoVo deviceInfoVo) {
        log.info("修改的信息{}", deviceInfoVo);
        DeviceInfoDto deviceInfoDto = deviceInfoService.selectDeviceInfo(deviceInfoVo.getUid());
        if(deviceInfoDto == null){
            throw new BusinessException(ResultEnum.DATA_NOT_EXIST);
        }
        LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new QueryWrapper<DeviceInfo>().lambda();
        deviceInfoLambdaQueryWrapper.eq(DeviceInfo::getUid, deviceInfoVo.getUid());
        DeviceInfo deviceInfo = new DeviceInfo();
        BeanUtils.copyProperties(deviceInfoVo, deviceInfo);
        deviceInfo.setUpdateTime(new Date());
        deviceInfo.update(deviceInfoLambdaQueryWrapper);
        //如果是激活状态，则可以发送mqtt
        if(!deviceInfoDto.getStatus().equals(DeviceStatusEnum.WAIT_ACTIVATE.getCode())){
            DeviceInfoDto getDeviceInfoDto = deviceInfoService.selectDeviceInfo(deviceInfoVo.getUid());
            deviceInfoLogic.publishDeviceInfo(getDeviceInfoDto);
        }
        return AjaxResult.success();
    }
}
